package com.gitee.deament.server.core.cli.db.list;

import cn.hutool.core.util.NumberUtil;
import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.data.ConnectData;
import com.gitee.deament.server.core.data.DBData;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import javax.jnlp.IntegrationService;
import java.util.ArrayList;
import java.util.List;

/**
 * LRANGE key start stop
 * 可用版本： >= 1.0.0
 * 时间复杂度: O(S+N)， S 为偏移量 start ， N 为指定区间内元素的数量。
 * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。
 *
 * 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
 *
 * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
 *
 * 注意LRANGE命令和编程语言区间函数的区别
 * 假如你有一个包含一百个元素的列表，对该列表执行 LRANGE list 0 10 ，结果是一个包含11个元素的列表，这表明 stop 下标也在 LRANGE 命令的取值范围之内(闭区间)，这和某些语言的区间函数可能不一致，比如Ruby的 Range.new 、 Array#slice 和Python的 range() 函数。
 *
 * # 超出范围的下标
 * 超出范围的下标值不会引起错误。
 *
 * 如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大，那么 LRANGE 返回一个空列表。
 *
 * 如果 stop 下标比 end 下标还要大，Redis将 stop 的值设置为 end 。
 *
 * 返回值
 * 一个列表，包含指定区间内的元素。
 * @author  deament
 */
@CliHander(command = "LRANGE")
public class LRANGEcli extends AbstractCli {
    @Override
    public void executeCli(ChannelHandlerContext channelHandlerContext, String command) {
        List<String> cliValues = getValues(command);
        if (cliValues.size() !=4) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'LRANGE' command"));
            return;
        }
        int db = ConnectData.SELECT_DB_STORAGE.getUseDB(channelHandlerContext.channel().id().asLongText());
        DBData dbData = SystemConfig.dbData;
        String key = cliValues.get(1);
        String start = cliValues.get(2);
        String stop = cliValues.get(3);
        if(!NumberUtil.isInteger(start) || Integer.parseInt(start)<0){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("start 参数错误"));
            return;
        }
        if(!NumberUtil.isInteger(stop) ){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("stop 参数错误"));
            return;
        }
        int startVal=Integer.parseInt(start);
        int stopVal= Integer.parseInt(stop);
        try {
            List<String> value = SystemConfig.dbData.getList(db, key).getValue();
            if(startVal>value.size()){
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("(nil)"));
                return ;
            }
            if(stopVal>value.size()){
                stopVal=value.size();
            }

            if(stopVal<0 && Math.abs(startVal)>value.size()){
                stopVal=0;
            }
            if(stopVal<0){
                stopVal=value.size()-Math.abs(stopVal)+1;
            }


            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(value.subList(startVal, stopVal).toString()));


        } catch (Exception e) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(e.getMessage()));
        }
    }

//    public static void main(String[] args) {
//        List<String> list =  new ArrayList<>();
//        list.add("a");
//        list.add("b");
//        list.add("c");
//        System.out.println(list.subList(0, 1));
//        System.out.println(list);
//    }
}
